package main.java.LeetCode.ClassicalAlgorithm.Worker.Impl.event;

import main.java.LeetCode.ClassicalAlgorithm.Queue.Queue;
import main.java.LeetCode.ClassicalAlgorithm.Worker.Event;
import main.java.LeetCode.ClassicalAlgorithm.Worker.Task;

import java.util.HashSet;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.ReentrantLock;

public class EventLoop implements Event,Runnable {

    private final boolean isCore;
    private final Queue<Task> queue;
    private final TimeUnit unit;
    private final long keepAlive;
    private Task firstTask;
    private final Thread thread;
    private AtomicInteger eventCounts;

    public EventLoop(Queue<Task> queue,boolean isCore,long keepAlive,TimeUnit unit){
        this.isCore = isCore;
        this.queue = queue;
        this.unit = unit;
        this.keepAlive = keepAlive;
        this.thread = new Thread(this);
    }

    public void setFirstTask(Task firstTask){
        this.firstTask = firstTask;
    }

    public Thread getThread(){
        return thread;
    }

    public void setEventCounts(AtomicInteger eventCounts){
        this.eventCounts = eventCounts;
    }

    public Task getFirstTask(){
        Task temp = this.firstTask;
        this.firstTask = null;
        return temp;
    }

    @Override
    public void run() {
        Task t;
        while (true) {
            if(this.thread.isInterrupted())
                break;

            try {
                boolean hasTask = isCore?((t = getFirstTask()) != null || (t = queue.get()) != null):
                        ((t = getFirstTask()) != null || (t = queue.get(keepAlive, unit)) != null);
                if (!hasTask)
                    break;

                t.doTask();

            } catch (InterruptedException e) {
                thread.interrupt();
            }
        }
        if(eventCounts!=null) {
            for (; ;) {
                int count = eventCounts.get();

                if (eventCounts.compareAndSet(count, count - 1))
                    break;
            }
        }

    }

    @Override
    public void go() {
        this.thread.start();
    }

    @Override
    public void submit(Task task){
        try {
            this.queue.set(task);
        }catch (InterruptedException e){
            e.printStackTrace(System.out);
        }
    }

    @Override
    public void shutdown(){
        this.thread.interrupt();
    }
}
